var worldWidth = 500;
var worldHeight = 500;
loop = null;
finished = false;

function init()
{
	prepareImages();
	var drawingBoard = $("drawingBoard");
	var scoreBoard = new ScoreBoard();
	var ctx = drawingBoard.getContext("2d");
	clearWorld(ctx);
	var ants = [];

	var world = { 'pheromones' : [], 'destination' : null, 'hive' : new Hive(ctx) };
	for (var i = 0; i < 100; i++)
	     ants.push(new Ant(ctx, world));

	world.finish = new Finish(ctx, ants, scoreBoard);
	world.obstacles = [new Bomb(ctx, world, ants), new Bomb(ctx, world, ants), 
				  				 new Bomb(ctx, world, ants)];
	world.ants = ants;
	world.scoreBoard = scoreBoard;

	var onclick = function(event) { world.destination = new Destination(event, ctx); }
	drawingBoard.addEventListener('click', onclick, true);
	
	finished = false;
	loop = gameLoop.periodical(30, null, [ctx, world, ants]);
}

function clearWorld(ctx)
{
	ctx.clearRect(0, 0, worldWidth, worldHeight);
}

function gameLoop(ctx, world, ants)
{
	if(ants.length <= 0 && world.scoreBoard.currentScore <= 0)
		alert("game over");
	if(finished)
		return;
	clearWorld(ctx);

	var redraw = function(item) 
	{ 
		if($defined(item))
			item.redraw(); 
	};
	[world.destination, world.hive, world.finish].each(redraw);
	[world.obstacles, world.pheromones].each(function(list) { list.each(redraw) });

	var walk = function(item)
	{
		if($defined(item))
		{
			item.walk();  
			item.redraw();
		}
	}
	ants.each(walk);
}

function ScoreBoard(ants)
{
	this.whiteBoard = $("scoreBoard");
	this.currentScore = 0;
	this.whiteBoard.innerHTML = this.currentScore;
}

ScoreBoard.prototype.score = function()
{
	this.currentScore++;
	this.whiteBoard.innerHTML = this.currentScore;
}

function Finish(ctx, ants, scoreBoard)
{
	this.img = new Image();
	this.img.src = "lightbulb_off.png";
	this.ants = ants;
	this.scoreBoard = scoreBoard;
	this.ctx = ctx;
	this.loc = randomLoc();
	this.redraw();
}

Finish.prototype.redraw = function()
{
	this.ctx.drawImage(this.img, this.loc.x, this.loc.y);
}

Finish.prototype.hasArrived = function(ant)
{
	this.ants.erase(ant);
	this.scoreBoard.score();
	if(this.ants.length <= 0)	
	{
		$clear(loop);
		finished = true;
		init();
	}
}

function Bomb(ctx, world, ants)
{
	this.triggerRange = 20;
	this.explosionRange = 100;
	this.ants = ants;
	this.img = new Image();
	this.img.src = "bomb.png";
	this.ctx = ctx;
	this.loc = randomLoc();
	this.world = world;
	this.ctx.drawImage(this.img, this.loc.x, this.loc.y);
}

Bomb.prototype.redraw = function()
{
	if(this.inTriggerRange())
	{
		this.killAnts()
		this.world.obstacles.erase(this);
	}
	else
	{
		this.ctx.drawImage(this.img, this.loc.x, this.loc.y);
	}
}

Bomb.prototype.inTriggerRange = function()
{
	for (var i = 0; i < this.ants.length; i++)
	{
		if(inRange(this, this.ants[i], this.triggerRange))
			return true;
	}
	return false;
}

Bomb.prototype.killAnts = function()
{
	for (var i = 0; i <  this.ants.length; i++)
	{
		if(inRange(this, this.ants[i], this.explosionRange))
			this.ants.erase(this.ants[i]);
	}
}

function prepareImages()
{ 
	var images = [ "lightning.png", "redbug.png", "lightbulb_off.png", 
					"redbug.png", "cog.png", "bomb.png" ];

	for(var i = 0; i < images.length; i++)
	{
		try
		{
			var img = new Image();
			img.src = images[i];
		}
		catch (ex) {}
	}
}

function Destination(event, ctx)
{
	this.ctx = ctx;
	this.img = new Image();
	this.img.src = "lightning.png";
	this.loc = { x: event.clientX, y: event.clientY };
	this.redraw();
}

Destination.prototype.hasArrived = function(ant)
{
	ant.lifeSpan--;
	ant.lookingFor = "hive";	
	ant.img = new Image();
	ant.img.src = "redbug.png";
}

Destination.prototype.redraw = function()
{
	this.ctx.drawImage(this.img, this.loc.x, this.loc.y);
}

function random(range)
{
	 return Math.floor(Math.random() * range);
}

function randomLoc(origin)
{
	 if(!$defined(origin))
		  return { x : random(worldWidth - 8), y : random(worldHeight - 8) };
	 return { x: origin.x + random(60) - 30, y: origin.y + random(60) - 30 };
}

function Hive(ctx)
{
	this.img = new Image();
	this.img.src = "cog.png";
	this.ctx = ctx;
	this.loc = randomLoc();
	this.redraw();
}

Hive.prototype.redraw = function()
{
	 this.ctx.drawImage(this.img, this.loc.x, this.loc.y);
}

Hive.prototype.hasArrived = function(ant)
{
	ant.lookingFor = "food";
	ant.img = new Image();
	ant.img.src = "bug.png";
}

function Ant(ctx, world)
{
	this.road = [];
	this.wandering = 5;
	this.currentWaypoint = null;
	this.world = world;
	this.lifeSpan = 30;
	this.smellRange = 100;
	this.lookingFor = "food";
	this.ctx = ctx;
	this.speed = 5;
    this.img = new Image();
	this.img.src = "bug.png";
    this.loc = randomLoc(world.hive.loc);
	ctx.drawImage(this.img, this.loc.x, this.loc.y);	
}

Ant.prototype.walk = function()
{
	var waypoint = this.currentWaypoint || this.getSmell();
	if(waypoint && random(5) != 0)
	{
		this.move(waypoint, 'x');
		this.move(waypoint, 'y');
		if(waypoint.loc.x == this.loc.x &&
			waypoint.loc.y == this.loc.y)
		{
			waypoint.hasArrived(this);	
			this.currentWaypoint = null;
		}
		else
		{
			this.currentWaypoint = waypoint;
		}
	}
	else
	{
		 this.loc.x += random(this.speed * 2) * (random(3) - 1);
		 this.loc.y += random(this.speed * 2) * (random(3)- 1);
	}
	this.leavePheromone();
}

Ant.prototype.move = function(waypoint, dir)
{
	if(waypoint.loc[dir] != this.loc[dir])
	{
		if(Math.abs(waypoint.loc[dir] - this.loc[dir]) < this.speed)
			this.loc[dir] += waypoint.loc[dir] - this.loc[dir];
		else
			this.loc[dir] += this.speed * (waypoint.loc[dir]> this.loc[dir] ? 1 : -1);
	}
}

Ant.prototype.leavePheromone = function()
{
	this.world.pheromones.push(new Pheromone(this.ctx, this, this.world));
}

Ant.prototype.getSmell = function()
{
	if(this.lookingFor == "food")
	{
		if (this.smell(this.world.finish))
		{
			return this.world.finish;
		}
		if(this.smell(this.world.destination))
		{
			return this.world.destination;
		}
		for (var i = 0; i < this.world.pheromones.length; i++)
		{
			if(this.smell(this.world.pheromones[i]))
			{
				return this.world.pheromones[i];
			}
		}
	}
	else if(this.lookingFor == "hive")
	{
		if(this.smell(this.world.hive))
		{
			return this.world.hive;
		}
		if(this.road.length > 0)
		{
			return this.road[this.road.length - 1];
		}
	}
	return null;
}


Ant.prototype.smell = function(obj)
{
	return inRange(obj, this, this.smellRange);
}

function inRange(obj1, obj2, range)
{
	return obj1 &&
			obj1.loc.x < obj2.loc.x + range &&
			obj1.loc.x > obj2.loc.x - range &&
			obj1.loc.y < obj2.loc.y + range &&
			obj1.loc.y > obj2.loc.y - range;
}

Ant.prototype.redraw = function()
{
	if(this.lifeSpan <= 0)
	{
		this.world.ants.erase(this);
		return;
	}
	this.ctx.drawImage(this.img, this.loc.x, this.loc.y);
}

function Pheromone(ctx, ant, world)
{
	this.world = world;
	this.power = 10;
	if(ant.lookingFor == "hive")
		this.power = 130;
	this.ctx = ctx;
	this.loc = { x: ant.loc.x, y: ant.loc.y };
}

Pheromone.prototype.hasArrived = function(ant)
{
	if(ant.lookingFor == "hive")
	{
		ant.road.pop();
	}
	else if(ant.lookingFor == "food")
	{
		ant.road.push(this);
	}
}

Pheromone.prototype.redraw = function()
{
	if(this.power == 0)
	{
		this.world.pheromones.erase(this);
		return;
	}
	this.power--;
}

window.onload = init;
